namespace Magecrawl.Utilities {
    using System;
    using System.Collections.Generic;

    public class Point : IEquatable<Point> {
        public static readonly Point Invalid = new Point( -1, -1 );

        public Point( int x, int y ) {
            this.X = x;
            this.Y = y;
        }

        public int X { get; set; }  // a field would be slightly faster.

        public int Y { get; set; }  // a field would be slightly faster.

        public static bool operator ==( Point lhs, Point rhs ) { return Equals( lhs, rhs ); }

        public static bool operator !=( Point lhs, Point rhs ) { return !Equals( lhs, rhs ); }

        public static Point operator +( Point lhs, Point rhs ) { return new Point( lhs.X + rhs.X, lhs.Y + rhs.Y ); }

        public static Point operator -( Point lhs, Point rhs ) { return new Point( lhs.X - rhs.X, lhs.Y - rhs.Y ); }

        /// <summary>
        /// I prefer one static comparer.
        /// </summary>
        public static bool Equals( Point thing1, Point thing2 ) {
            return thing1.X == thing2.X && thing1.Y == thing2.Y;
        }

        public override int GetHashCode() { unchecked { return ( this.X * 397 ) ^ this.Y; } }

        public override string ToString() { return string.Format( "({0},{1})", this.X, this.Y ); }

        public bool IsInRange( Point upperLeft, Point lowerRight ) { return this.X >= upperLeft.X && this.X <= lowerRight.X && this.Y >= upperLeft.Y && this.Y <= lowerRight.Y; }

        public bool Equals( Point other ) {
            return Equals( this, other );
        }

        public override bool Equals( object obj ) {
            return Equals( this, obj as Point );
        }

    }

    public class PointEqualityComparer : IEqualityComparer<Point> {
        public static PointEqualityComparer Instance = new PointEqualityComparer();

        public bool Equals( Point x, Point y ) { return x == y; }

        public int GetHashCode( Point obj ) { return obj.GetHashCode(); }
    }
}
